/*=======================================================
Critical Links
Auto Configuration Server

Authors:
	Rui Eduardo Gouveia Gil - r-gil@critical-links.com

Date: 2010
Version 0.1
=======================================================*/
#include "httpd/HttpACSInterface.h"
#include "httpd/HttpUserManager.h"
#include "httpd/DiskFileSender.h"
#include "database/DataBase.h"
#include "ACSConfig.h"

namespace acs
{

unsigned int HttpACSInterface::seqID = 0;
rgcpp::Sequence<int> HttpACSInterface::fileID(1);
std::string HttpACSInterface::TMP_FILE_PEFIX="/tmp/eacs_backup_";

HttpACSInterface::HttpACSInterface()
{

}

HttpACSInterface::~HttpACSInterface()
{

}
void HttpACSInterface::operator()(pion::net::HTTPRequestPtr& request, pion::net::TCPConnectionPtr& tcpConn)
{
	HttpUserThreadBind httpUserThreadBind(request->getUser());

	if(request->getMethod().compare("POST") == 0)
	{
		try
		{
			this->handlerPostRequest(request,tcpConn);
		}
		catch(rgcpp::Exception& e)
		{
			pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
			writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
			writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
			writer->send();
		}
	}
	if(request->getMethod().compare("PUT") == 0)
	{
		try
		{
			std::string license = request->getQuery("license");

			if(DataBase::getInstance()->existsDeviceWithLicense(license))
			{
				Device device = DataBase::getInstance()->getDeviceWithLicense(license);
				std::string tempFile = HttpACSInterface::TMP_FILE_PEFIX+rgcpp::ToString(HttpACSInterface::fileID.getNextSequenceId());
				std::string destFile = ACSConfig::getDataDirectory()+std::string("Device_Backup_")+rgcpp::ToString(device.getID());

				rgcpp::FileLock fileLock(ACSConfig::getDataDirectory()+std::string("Device_Backup_")+rgcpp::ToString(device.getID())+".lock");

				{std::ofstream stream(tempFile.c_str(),std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);

				if(!stream.good())
				{
					Throw(rgcpp::RuntimeException("Invalid temporary file."));
				}

				stream.write(request->getContent(),request->getContentLength());

				stream.close();}

				if(boost::filesystem::exists(destFile))
					boost::filesystem::remove(destFile);
				boost::filesystem::copy_file(tempFile,destFile);
			}

			pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
			writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_OK);
			writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_OK);
			writer->send();
		}
		catch(rgcpp::Exception& e)
		{
			pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
			writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
			writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
			writer->send();
		}
	}
	else if(request->getMethod().compare("GET") == 0)
	{
		std::string license = request->getQuery("license");
		std::string backup = request->getQuery("backup");

		LOG_DEBUG_DATA("Getting restore file for device with license " << license);

		if(DataBase::getInstance()->existsDeviceWithLicense(license))
		{
			if(backup.compare("yes") == 0)
			{
				Device device = DataBase::getInstance()->getDeviceWithLicense(license);
				if(device.getLastBackup() == 0)
				{
					LOG_WARN_DATA("Not found device backup file with license " << license);
					pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
					writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_FORBIDDEN);
					writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_FORBIDDEN);
					writer->send();
				}
				else
				{
					const std::string if_modified_since(request->getHeader(pion::net::HTTPTypes::HEADER_IF_MODIFIED_SINCE));

					rgcpp::FileLock fileLock(ACSConfig::getDataDirectory()+std::string("Device_Backup_")+rgcpp::ToString(device.getID())+".lock");

					DiskFile responseFile;
					responseFile.setFilePath(ACSConfig::getDataDirectory()+std::string("Device_Backup_")+rgcpp::ToString(device.getID()));
					responseFile.setMimeType("application/x-compressed");
					responseFile.update();

					if (responseFile.getLastModifiedString() == if_modified_since)
					{
						pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
						writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_NOT_MODIFIED);
						writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_NOT_MODIFIED);
						writer->send();
					}
					else
					{
						LOG_DEBUG_DATA("Sending restore for device with license " << license);
						boost::shared_ptr<DiskFileSender> sender_ptr(DiskFileSender::create(responseFile,request,tcpConn,0));
						sender_ptr->send();
					}
				}
			}
			else
			{
				Device device = DataBase::getInstance()->getDeviceWithLicense(license);
				Configuration config =  DataBase::getInstance()->getConfiguration(device.getConfigID());
				if(config.getConfigFileName().empty())
				{
					LOG_WARN_DATA("Not found device restore file with license " << license);
					pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
					writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_FORBIDDEN);
					writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_FORBIDDEN);
					writer->send();
				}
				else
				{
					const std::string if_modified_since(request->getHeader(pion::net::HTTPTypes::HEADER_IF_MODIFIED_SINCE));

					rgcpp::FileLock fileLock(ACSConfig::getDataDirectory()+std::string("Configuration_BackupRestore_")+rgcpp::ToString(config.getID())+".lock");

					DiskFile responseFile;
					responseFile.setFilePath(ACSConfig::getDataDirectory()+std::string("Configuration_BackupRestore_")+rgcpp::ToString(config.getID()));
					responseFile.setMimeType(rgcpp::MIMETypes::findMIMEType(config.getConfigFileName()));
					responseFile.update();

					if (responseFile.getLastModifiedString() == if_modified_since)
					{
						pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
						writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_NOT_MODIFIED);
						writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_NOT_MODIFIED);
						writer->send();
					}
					else
					{
						LOG_DEBUG_DATA("Sending restore for device with license " << license);
						boost::shared_ptr<DiskFileSender> sender_ptr(DiskFileSender::create(responseFile,request,tcpConn,0));
						sender_ptr->send();
					}
				}
			}
		}
		else
		{
			LOG_WARN_DATA("Not found device with license " << license);
			pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));
			writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
			writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
			writer->send();
		}
	}
}

void HttpACSInterface::handlerPostRequest(pion::net::HTTPRequestPtr& request, pion::net::TCPConnectionPtr& tcpConn)
{
	std::string name;
	std::string result;
	TiXmlDocument xmlDocument;
	xmlDocument.Parse(request->getContent());
	std::string license = request->getQuery("license");
	std::string ip = tcpConn.get()->getRemoteIp().to_string();

	LOG_DEBUG_DATA("From: " << ip << " with license = " << license << "\n" << request->getContent());

	TiXmlElement* message = xmlDocument.FirstChildElement("Message");
	if(message == NULL)
	{
		Throw(rgcpp::IllegalArgumentException(std::string("Invalid xml: element <Message> missing.")));
	}

	TiXmlElement* command = message->FirstChildElement("Command");
	if(command == NULL)
	{
		Throw(rgcpp::IllegalArgumentException(std::string("Invalid xml: element <Command> missing.")));
	}

	pion::net::HTTPResponseWriterPtr writer(pion::net::HTTPResponseWriter::create(tcpConn, *request, boost::bind(&pion::net::TCPConnection::finish, tcpConn)));

	if(command->Attribute("name"))
	{
		name = command->Attribute("name");
		std::transform(name.begin(),name.end(),name.begin(),::tolower);
	}

	if(name.compare("inform") == 0 || name.compare("boot") == 0)
		result = this->handlerPostRequestInform(request,writer,message,command,name,license,ip);
	else if(name.compare("backup") == 0)
		result = this->handlerPostRequestBackup(request,writer,message,command,name,license,ip);
	else if(name.compare("restore") == 0)
		result = this->handlerPostRequestRestore(request,writer,message,command,name,license,ip);
	else if(name.compare("bulk") == 0)
		result = this->handlerPostRequestBulkCommands(request,writer,message,command,name,license,ip);
	else
		result = this->handlerPostRequestCommand(request,writer,message,command,name,license,ip);

	boost::trim(result);

	LOG_DEBUG_DATA("To: " << ip << " with license = " << license << "\n" << result);

	if(result.empty())
	{
		writer->getResponse().setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_NO_CONTENT);
		writer->getResponse().setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_NO_CONTENT);
	}
	else
	{
		writer->getResponse().setContentType("text/plain");
		writer->write(result);
		writer->write(pion::net::HTTPTypes::STRING_CRLF);
		writer->write(pion::net::HTTPTypes::STRING_CRLF);
	}
	writer->send();
}

std::string HttpACSInterface::handlerPostRequestInform(pion::net::HTTPRequestPtr& request, pion::net::HTTPResponseWriterPtr& writer, const TiXmlElement* message, const TiXmlElement* command, const std::string& name, const std::string& license, const std::string& ip)
{
	std::string result;

	std::string firstConfig;
	std::time_t lastLocalChange;
	std::string lastRestore;
	std::string lastUpdate;
    std::string customerName;
    std::string maxUsers;
    std::string licenseID;
    std::string hardwareDescription;
    std::string release;
    std::string build;
    std::string pepsVersion;
    std::string guiVersion;
    std::string upTime;
    std::string systemLoad;
    std::string installedMemory;
    std::string freeMemory;
    std::string swapUsed;
    std::string partitionVar;
    std::string partitionRoot;
    std::string partitionHome;

    std::string aname;
    const TiXmlNode* node = command->FirstChild("Argument");
    while(node && node->ToElement())
    {
    	if(node->ToElement()->Attribute("name"))
    	{
    		aname = node->ToElement()->Attribute("name");
    		boost::trim(aname);
    		std::transform(aname.begin(),aname.end(),aname.begin(),::tolower);

    		if(aname.compare("firstconfig") == 0)
    			firstConfig = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("lastlocalchange") == 0)
    			lastLocalChange = atoi(node->FirstChild()->ToText()->Value());
    		else if(aname.compare("lastrestore") == 0)
    			lastRestore = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("lastupdate") == 0)
    			lastUpdate = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("customername") == 0)
				customerName = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("maxusers") == 0)
				maxUsers = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("licenseid") == 0)
				licenseID = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("hardwaredescription") == 0)
				hardwareDescription = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("release") == 0)
				release = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("build") == 0)
				build = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("peps version") == 0)
				pepsVersion = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("gui version") == 0)
    			guiVersion = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("up time") == 0)
				upTime = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("system load") == 0)
				systemLoad = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("installed memory") == 0)
				installedMemory = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("free memory") == 0)
				freeMemory = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("swap used") == 0)
				swapUsed = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("partition /var") == 0)
				partitionVar = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("partition /") == 0)
				partitionRoot = node->FirstChild()->ToText()->Value();
    		else if(aname.compare("partition /home") == 0)
				partitionHome = node->FirstChild()->ToText()->Value();
    	}

    	node = command->IterateChildren("Argument",node);
    }

	if(DataBase::getInstance()->existsDeviceWithLicense(license))
	{
		Device device = DataBase::getInstance()->getDeviceWithLicense(license);

		if(name.compare("boot") == 0)
			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","CPE :: System boot."),true);

		if(device.onActionPeriod())
		{
			if(device.getConfigMode() ==  DCM_AUTOMATIC_CONFIG_IF_NO_CONFLICTS  && lastLocalChange != device.getLocalChange())
			{
				device.setStatus(DS_PENDING_CONFIRMATION);
				DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"configuration conflicts",license,device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Device configuration was manually changed."));
			}

			if((device.getConfigMode() !=  DCM_AUTOMATIC_FIRST_CONFIG && device.getStatus() != DS_PENDING_VALIDATION && device.getStatus() != DS_PENDING_CONFIRMATION) || (device.getConfigMode() ==  DCM_AUTOMATIC_FIRST_CONFIG && firstConfig.compare("yes") == 0))
			{
				Configuration config =  DataBase::getInstance()->getConfiguration(device.getConfigID());
				if(device.getStatus() == DS_PENDING_BACKUP || device.getStatus() == DS_PENDING_BACKUP_WITH_SOUNDS)
				{
					writer->getResponse().setCookie(COOKIE_DEVICE_ID,rgcpp::ToString(device.getID()),"");
					writer->getResponse().setCookie(COOKIE_DEVICE_1ST_CONFIG,firstConfig);
					writer->getResponse().setCookie(COOKIE_DEVICE_LAST_UPDATE,lastUpdate,"");
					writer->getResponse().setCookie(COOKIE_DEVICE_LAST_RESTORE,lastRestore,"");
					writer->getResponse().setCookie(COOKIE_DEVICE_BACKUP_MODE,rgcpp::ToString(device.getStatus() ),"");

					device.setStatus(DS_EXECUTING_BACKUP);
					std::vector<std::string> args;
					args.push_back(rgcpp::ToString((int)(device.getStatus() == DS_PENDING_BACKUP_WITH_SOUNDS)));
					result = this->buildMessage(Command(0,"backup",args));
					DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Begin backup."));
				}
				else if(!config.getConfigFileName().empty() && lastRestore.compare(config.getSHA()))
				{
					writer->getResponse().setCookie(COOKIE_DEVICE_ID,rgcpp::ToString(device.getID()),"");
					writer->getResponse().setCookie(COOKIE_DEVICE_1ST_CONFIG,firstConfig);

					device.setStatus(DS_EXECUTING_TASKS);
					Configuration config =  DataBase::getInstance()->getConfiguration(device.getConfigID());
					std::vector<std::string> args;
					args.push_back(rgcpp::ToString(config.isRWan()));
					args.push_back(rgcpp::ToString(config.isRUsers()));
					result = this->buildMessage(Command(0,"restore",args));
					if(firstConfig.compare("yes") == 0)
					{
						DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Requesting 1st configuration."));
						DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending 1st configuration."));
					}
					else
					{
						DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available."));
						DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending configuration."));
					}
					DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","ACS :: Executing configuration restore."));
				}
				else if(lastUpdate.compare(this->getDeviceSHA(device.getID())) != 0)
				{
					if(DataBase::getInstance()->existDeviceCommand(device.getID(),0))
					{
						writer->getResponse().setCookie(COOKIE_DEVICE_ID,rgcpp::ToString(device.getID()),"");
						writer->getResponse().setCookie(COOKIE_DEVICE_1ST_CONFIG,firstConfig);

						device.setStatus(DS_EXECUTING_TASKS);
						result = this->buildMessage(DataBase::getInstance()->getDeviceCommands(device.getID()));
						if(name.compare("boot") != 0 && firstConfig.compare("yes") == 0)
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Requesting 1st configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending 1st configuration."));
						}
						else if(name.compare("boot") != 0)
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending configuration."));
						}
						DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","ACS :: Executing commands."));
					}
					else
					{
						if(name.compare("boot") != 0 && firstConfig.compare("yes") == 0)
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Requesting 1st configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending 1st configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: First configuration done."));
						}
						else if(name.compare("boot") != 0)
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Configuration done."));
						}

						device.setStatus(DS_SYNCHRONIZED);
						result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
					}
				}
				else//Synchronized
				{
					if(device.getStatus() == DS_PENDING_TASKS)
					{
						device.setStatus(DS_SYNCHRONIZED);
						result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
						if(firstConfig.compare("yes") == 0)
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Requesting 1st configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending 1st configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: First configuration done."));
						}
						else
						{
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Sending configuration."));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Configuration done."));
						}
					}
					else
					{
						device.setStatus(DS_SYNCHRONIZED);
						result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
					}
				}
			}
			else if(device.getConfigMode() ==  DCM_AUTOMATIC_FIRST_CONFIG && firstConfig.compare("yes") != 0)
			{
				if(device.getStatus() == DS_PENDING_VALIDATION)
				{
					result = this->buildMessageError(std::string("Device not validated - license ")+license);
					DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"not validated",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Device needs validation."));
				}
				else if(device.getStatus() == DS_PENDING_BACKUP || device.getStatus() == DS_PENDING_BACKUP_WITH_SOUNDS)
				{
					writer->getResponse().setCookie(COOKIE_DEVICE_ID,rgcpp::ToString(device.getID()),"");
					writer->getResponse().setCookie(COOKIE_DEVICE_1ST_CONFIG,firstConfig);
					writer->getResponse().setCookie(COOKIE_DEVICE_LAST_UPDATE,lastUpdate,"");
					writer->getResponse().setCookie(COOKIE_DEVICE_LAST_RESTORE,lastRestore,"");
					writer->getResponse().setCookie(COOKIE_DEVICE_BACKUP_MODE,rgcpp::ToString(device.getStatus() ),"");

					device.setStatus(DS_EXECUTING_BACKUP);
					std::vector<std::string> args;
					args.push_back(rgcpp::ToString((int)(device.getStatus() == DS_PENDING_BACKUP_WITH_SOUNDS)));
					result = this->buildMessage(Command(0,"backup",args));
					DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Begin device backup."));
				}
				else
				{
					result = this->buildMessageError(std::string("Device in first config mode - license ")+license);
					DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"invalid change mode",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Device configuration mode mismatch."));
				}
			}
			else if(device.getConfigMode() !=  DCM_AUTOMATIC_FIRST_CONFIG && firstConfig.compare("yes") == 0)
			{
				result = this->buildMessageError(std::string("Device not first config mode - license ")+license);
				DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"invalid change mode",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Device configuration mode mismatch."));
			}
			else if(device.getConfigMode() !=  DCM_AUTOMATIC_FIRST_CONFIG && device.getStatus() == DS_PENDING_CONFIRMATION)
			{
				result = this->buildMessageError(std::string("Pending confirmation - license ")+license);
				DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"pending confirmation",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available. Pending confirmation."));
			}
			else if(device.getConfigMode() !=  DCM_AUTOMATIC_FIRST_CONFIG && device.getStatus() == DS_PENDING_VALIDATION)
			{
				result = this->buildMessageError(std::string("Device needs validation - license ")+license);
				DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"not validated",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Device needs validation."));
			}
			else
			{
				result = this->buildMessageError(std::string("Invalid device state - license ")+license);
				DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,"invalid device state",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Invalid device state."));
			}
		}

		device.setIp(ip);
		device.setBuild(build);
		device.setUpTime(upTime);
		device.setRelease(release);
		device.setSwapUsed(swapUsed);
		device.setMaxUsers(maxUsers);
		device.setLicenseID(licenseID);
		device.setSystemLoad(systemLoad);
		device.setGuiVersion(guiVersion);
		device.setFreeMemory(freeMemory);
		device.setPepsVersion(pepsVersion);
		device.setCustomerName(customerName);
		device.setPartitionVar(partitionVar);
		device.setPartitionRoot(partitionRoot);
		device.setPartitionHome(partitionHome);
		device.setLocalChange(lastLocalChange);
		device.setInstalledMemory(installedMemory);
		device.setHardwareDescription(hardwareDescription);
		DataBase::getInstance()->updateContact(device);
	}
	else
	{
		if(!licenseID.empty())
		{
			DataBase::getInstance()->checkDefaults();

			time_t current;
			time(&current);

			Device device;
			device.setStatus(DS_PENDING_VALIDATION);
			device.setName(customerName+"-"+licenseID);
			device.setBuild(build);
			device.setUpTime(upTime);
			device.setRelease(release);
			device.setSwapUsed(swapUsed);
			device.setMaxUsers(maxUsers);
			device.setContacted(current);
			device.setLicenseID(licenseID);
			device.setSystemLoad(systemLoad);
			device.setGuiVersion(guiVersion);
			device.setFreeMemory(freeMemory);
			device.setPepsVersion(pepsVersion);
			device.setCustomerName(customerName);
			device.setPartitionVar(partitionVar);
			device.setPartitionRoot(partitionRoot);
			device.setPartitionHome(partitionHome);
			device.setLocalChange(lastLocalChange);
			device.setInstalledMemory(installedMemory);
			device.setHardwareDescription(hardwareDescription);
			device = DataBase::getInstance()->createDevice(device);

			result = this->buildMessageError(std::string("Device needs validation - license ")+license);
			if(firstConfig.compare("yes") == 0)
				DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Requesting 1st configuration."));
			else
				DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available."));
			DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"",device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: Device needs validation"));
		}
	}

	return result;
}

std::string HttpACSInterface::handlerPostRequestBackup(pion::net::HTTPRequestPtr& request, pion::net::HTTPResponseWriterPtr& writer, const TiXmlElement* message, const TiXmlElement* command, const std::string& name, const std::string& license, const std::string& ip)
{
	std::string result;

	int deviceID = atoi(request.get()->getCookie(COOKIE_DEVICE_ID).c_str());
	std::string lastUpdate = request.get()->getCookie(COOKIE_DEVICE_LAST_UPDATE);
	std::string lastRestore = request.get()->getCookie(COOKIE_DEVICE_LAST_RESTORE);
	DeviceStatus deviceStatus =  (DeviceStatus)atoi(request.get()->getCookie(COOKIE_DEVICE_BACKUP_MODE).c_str());
	if(deviceID != 0 && DataBase::getInstance()->existsDevice(deviceID))
	{
		Device device = DataBase::getInstance()->getDevice(deviceID);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			rgcpp::FileLock fileLock(ACSConfig::getDataDirectory()+std::string("Device_Backup_")+rgcpp::ToString(device.getID())+".lock");
			device.updateLastBackup();
			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Device backup created."));

			if(device.onActionPeriod())
			{
				if(device.getConfigMode() !=  DCM_AUTOMATIC_FIRST_CONFIG)
				{
					Configuration config =  DataBase::getInstance()->getConfiguration(device.getConfigID());
					if(device.getConfigMode() == DCM_MANUAL)
					{
						if(!config.getConfigFileName().empty() && lastRestore.compare(config.getSHA()) || lastUpdate.compare(this->getDeviceSHA(device.getID())) != 0 && DataBase::getInstance()->existDeviceCommand(device.getID(),0))
						{
							device.setStatus(DS_PENDING_CONFIRMATION);
							result = this->buildMessageError(std::string("Pending confirmation - license ")+license);
							DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,device.getID(),ip,"pending confirmation",license,device.getRelease(),device.getCustomerName(),name,"Fail","ACS :: New configuration available. Pending confirmation."));
						}
						else//Synchronized
						{
							device.setStatus(DS_SYNCHRONIZED);
							result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
						}
					}
					else
					{
						if(!config.getConfigFileName().empty() && lastRestore.compare(config.getSHA()))
						{
							device.setStatus(DS_EXECUTING_TASKS);
							Configuration config =  DataBase::getInstance()->getConfiguration(device.getConfigID());
							std::vector<std::string> args;
							args.push_back(rgcpp::ToString(config.isRWan()));
							args.push_back(rgcpp::ToString(config.isRUsers()));
							result = this->buildMessage(Command(0,"restore",args));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","ACS :: Executing configuration restore."));
						}
						else if(lastUpdate.compare(this->getDeviceSHA(device.getID())) != 0 && DataBase::getInstance()->existDeviceCommand(device.getID(),0))
						{
							device.setStatus(DS_EXECUTING_TASKS);
							result = this->buildMessage(DataBase::getInstance()->getDeviceCommands(device.getID()));
							DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","ACS :: Executing commands."));
						}
						else//Synchronized
						{
							device.setStatus(DS_SYNCHRONIZED);
							result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
						}
					}
				}
				else//Synchronized
				{
					device.setStatus(DS_SYNCHRONIZED);
					result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));
				}
			}
		}
		else
		{
			device.setStatus((deviceStatus == DS_PENDING_BACKUP_WITH_SOUNDS ? DS_PENDING_BACKUP_WITH_SOUNDS : DS_PENDING_BACKUP));
			result = this->buildMessageError("Unable to create device backup.");
			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Unable to create device backup."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else
	{
		result = this->buildMessageError(std::string("Device not found - id ")+rgcpp::ToString(deviceID));
		DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,0,ip,"not found",license,"","",name,"Fail","ACS :: Device not found."));
	}

	return result;
}

std::string HttpACSInterface::handlerPostRequestRestore(pion::net::HTTPRequestPtr& request, pion::net::HTTPResponseWriterPtr& writer, const TiXmlElement* message, const TiXmlElement* command, const std::string& name, const std::string& license, const std::string& ip)
{
	std::string result;

	int deviceID = atoi(request.get()->getCookie(COOKIE_DEVICE_ID).c_str());
	if(deviceID != 0 && DataBase::getInstance()->existsDevice(deviceID))
	{
		Device device = DataBase::getInstance()->getDevice(deviceID);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			device.updateLastRestore();
			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Restore succeeded."));
			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),"inform","Status","CPE :: Beginning reboot."));
		}
		else
		{
			device.setStatus(DS_PENDING_TASKS);
			result = this->buildMessageError("Unable to restore backup.");
			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Restore failed."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else
	{
		result = this->buildMessageError(std::string("Device not found - id ")+rgcpp::ToString(deviceID));
		DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,0,ip,"not found",license,"","",name,"Fail","ACS :: Device not found."));
	}

	return result;
}

std::string HttpACSInterface::handlerPostRequestCommand(pion::net::HTTPRequestPtr& request, pion::net::HTTPResponseWriterPtr& writer, const TiXmlElement* message, const TiXmlElement* command, const std::string& name, const std::string& license, const std::string& ip)
{
	std::string result;
	int deviceID = atoi(request.get()->getCookie(COOKIE_DEVICE_ID).c_str());
	std::string firstConfig = request.get()->getCookie(COOKIE_DEVICE_1ST_CONFIG);
	if(deviceID != 0 && DataBase::getInstance()->existsDevice(deviceID))
	{
		int commandIndex = atoi(request.get()->getCookie(COOKIE_COMMAND_INDEX).c_str());
		Device device = DataBase::getInstance()->getDevice(deviceID);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			std::string message;
			const TiXmlNode* returnE = command->FirstChild("Return");
			if(returnE != NULL)
				message = "Return: ";
			while(returnE != NULL)
			{
				message += returnE->FirstChild()->ToText()->Value();
				returnE = command->IterateChildren("Return",returnE);
				if(returnE != NULL)
					message += " | ";
			}

			const TiXmlNode* warning = command->FirstChild("Warning");
			if(warning != NULL)
				message += " Warning: ";

			while(warning != NULL)
			{
				message += warning->FirstChild()->ToText()->Value();
				warning = command->IterateChildren("Warning",warning);
				if(warning != NULL)
					message += " | ";
			}

			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Command execution succeeded."));

			if(DataBase::getInstance()->existDeviceCommand(deviceID,commandIndex))
			{
				result = this->buildMessage(DataBase::getInstance()->getDeviceCommand(deviceID,commandIndex));
				commandIndex++;
				writer->getResponse().setCookie(COOKIE_COMMAND_INDEX,rgcpp::ToString(commandIndex),"");
			}
			else
			{
				device.setStatus(DS_SYNCHRONIZED);
				result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));

				if(firstConfig.compare("yes") == 0)
					DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: First configuration done."));
				else
					DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Configuration done."));
			}
		}
		else
		{
			std::string message;
			const TiXmlNode* error = command->FirstChild("Error");
			if(error != NULL)
				message = "Error: ";
			while(error != NULL)
			{
				message += error->FirstChild()->ToText()->Value();
				error = command->IterateChildren("Error",error);
				if(error != NULL)
					message += " | ";
			}

			result = this->buildMessageError("Error executing command.");
			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Command execution failed."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else if(DataBase::getInstance()->existsDeviceWithLicense(license))
	{
		Device device = DataBase::getInstance()->getDeviceWithLicense(license);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			std::string message;
			const TiXmlNode* returnE = command->FirstChild("Return");
			if(returnE != NULL)
				message = "Return: ";
			while(returnE != NULL)
			{
				message += returnE->FirstChild()->ToText()->Value();
				returnE = command->IterateChildren("Return",returnE);
				if(returnE != NULL)
					message += " | ";
			}

			const TiXmlNode* warning = command->FirstChild("Warning");
			if(warning != NULL)
				message += " Warning: ";

			while(warning != NULL)
			{
				message += warning->FirstChild()->ToText()->Value();
				warning = command->IterateChildren("Warning",warning);
				if(warning != NULL)
					message += " | ";
			}

			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Command execution succeeded."));
		}
		else
		{
			std::string message;
			const TiXmlNode* error = command->FirstChild("Error");
			if(error != NULL)
				message = "Error: ";
			while(error != NULL)
			{
				message += error->FirstChild()->ToText()->Value();
				error = command->IterateChildren("Error",error);
				if(error != NULL)
					message += " | ";
			}

			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Command execution failed."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else
	{
		result = this->buildMessageError(std::string("Device not found - license ")+license);
		DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,0,ip,"not found",license,"","",name,"Fail","ACS :: Device not found."));
	}

	return result;
}

std::string HttpACSInterface::handlerPostRequestBulkCommands(pion::net::HTTPRequestPtr& request, pion::net::HTTPResponseWriterPtr& writer, const TiXmlElement* message, const TiXmlElement* command, const std::string& name, const std::string& license, const std::string& ip)
{
	std::string result;
	int deviceID = atoi(request.get()->getCookie(COOKIE_DEVICE_ID).c_str());
	std::string firstConfig = request.get()->getCookie(COOKIE_DEVICE_1ST_CONFIG);
	if(deviceID != 0 && DataBase::getInstance()->existsDevice(deviceID))
	{
		Device device = DataBase::getInstance()->getDevice(deviceID);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			std::string message;
			const TiXmlNode* returnE = command->FirstChild("Return");
			if(returnE != NULL)
				message = "Return: ";
			while(returnE != NULL)
			{
				message += returnE->FirstChild()->ToText()->Value();
				returnE = command->IterateChildren("Return",returnE);
				if(returnE != NULL)
					message += " | ";
			}

			const TiXmlNode* warning = command->FirstChild("Warning");
			if(warning != NULL)
				message += " Warning: ";

			while(warning != NULL)
			{
				message += warning->FirstChild()->ToText()->Value();
				warning = command->IterateChildren("Warning",warning);
				if(warning != NULL)
					message += " | ";
			}

			device.setStatus(DS_SYNCHRONIZED);
			result = this->buildMessageSynchronized(this->getDeviceSHA(device.getID()));

			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Commands execution succeeded."));

			if(firstConfig.compare("yes") == 0)
				DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: First configuration done."));
			else
				DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Status","ACS :: Configuration done."));
		}
		else
		{
			std::string message;
			const TiXmlNode* error = command->FirstChild("Error");
			if(error != NULL)
				message = "Error: ";
			while(error != NULL)
			{
				message += error->FirstChild()->ToText()->Value();
				error = command->IterateChildren("Error",error);
				if(error != NULL)
					message += " | ";
			}

			result = this->buildMessageError("Error executing command.");

			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Commands execution failed."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else if(DataBase::getInstance()->existsDeviceWithLicense(license))
	{
		Device device = DataBase::getInstance()->getDeviceWithLicense(license);

		if(command->Attribute("result") && std::string(command->Attribute("result")).compare("success") == 0)
		{
			std::string message;
			const TiXmlNode* returnE = command->FirstChild("Return");
			if(returnE != NULL)
				message = "Return: ";
			while(returnE != NULL)
			{
				message += returnE->FirstChild()->ToText()->Value();
				returnE = command->IterateChildren("Return",returnE);
				if(returnE != NULL)
					message += " | ";
			}

			const TiXmlNode* warning = command->FirstChild("Warning");
			if(warning != NULL)
				message += " Warning: ";

			while(warning != NULL)
			{
				message += warning->FirstChild()->ToText()->Value();
				warning = command->IterateChildren("Warning",warning);
				if(warning != NULL)
					message += " | ";
			}

			DataBase::getInstance()->addLog(Log(ACS_LL_NOTICE,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Success","CPE :: Commands execution succeeded."));
		}
		else
		{
			std::string message;
			const TiXmlNode* error = command->FirstChild("Error");
			if(error != NULL)
				message = "Error: ";
			while(error != NULL)
			{
				message += error->FirstChild()->ToText()->Value();
				error = command->IterateChildren("Error",error);
				if(error != NULL)
					message += " | ";
			}

			DataBase::getInstance()->addLog(Log(ACS_LL_ERROR,device.getID(),ip,device.getName(),device.getLicenseID(),device.getRelease(),device.getCustomerName(),name,"Fail","CPE :: Commands execution failed."));
		}

		DataBase::getInstance()->updateContact(device);
	}
	else
	{
		result = this->buildMessageError(std::string("Device not found - license ")+license);
		DataBase::getInstance()->addLog(Log(ACS_LL_WARNING,0,ip,"not found",license,"","",name,"Fail","ACS :: Device not found."));
	}

	return result;
}

std::string HttpACSInterface::buildMessageSynchronized(const std::string& sha)
{
	Command command;
	command.setCommand("synchronized");

	std::vector<std::string> arguments;
	arguments.push_back(sha);
	command.setArguments(arguments);

	return this->buildMessage(command);
}

std::string HttpACSInterface::buildMessageError(const std::string& error)
{
	Command command;
	command.setCommand("error");

	std::vector<std::string> arguments;
	arguments.push_back(error);
	command.setArguments(arguments);

	return this->buildMessage(command);
}

std::string HttpACSInterface::buildMessage(const Command& action)
{
	std::string xmlStr;

	try
	{
		TiXmlDocument xmlDocument;

		TiXmlElement* message = new TiXmlElement("Message");
		message->SetAttribute("service","acs");
		xmlDocument.LinkEndChild(message);

		TiXmlElement* command = new TiXmlElement("Command");
		command->SetAttribute("name",action.getCommand().c_str());
		command->SetAttribute("seqID",rgcpp::ToString(HttpACSInterface::seqID++).c_str());
		command->SetAttribute("sync","yes");
		message->LinkEndChild(command);

		std::vector<std::string> arguments = action.getArguments();
		for(std::vector<std::string>::iterator itr = arguments.begin(); itr!=arguments.end(); itr++)
		{
			TiXmlElement* license = new TiXmlElement("Argument");
			license->LinkEndChild(new TiXmlText(itr->c_str()));
			command->LinkEndChild(license);
		}

		TiXmlPrinter printer;
		printer.SetIndent("    ");
		xmlDocument.Accept(&printer);

		xmlStr = printer.CStr();
	}
	catch(std::exception& e)
	{
		Throw(rgcpp::IllegalArgumentException(std::string("Unable to create rpc inform request xml - ")+e.what()));
	}

	return xmlStr;
}

std::string HttpACSInterface::buildMessage(const std::vector<Command>& actions)
{
	std::string xmlStr;

	try
	{
		TiXmlDocument xmlDocument;

		TiXmlElement* message = new TiXmlElement("Message");
		message->SetAttribute("service","acs");
		xmlDocument.LinkEndChild(message);

		TiXmlElement* command = new TiXmlElement("Command");
		command->SetAttribute("name","bulk");
		command->SetAttribute("seqID",rgcpp::ToString(HttpACSInterface::seqID++).c_str());
		command->SetAttribute("sync","yes");
		message->LinkEndChild(command);

		for(std::vector<Command>::const_iterator itr = actions.begin(); itr!=actions.end(); itr++)
		{
			TiXmlElement* license = new TiXmlElement("Argument");
			license->LinkEndChild(new TiXmlText(this->buildMessage(*itr).c_str()));
			command->LinkEndChild(license);
		}

		TiXmlPrinter printer;
		printer.SetIndent("    ");
		xmlDocument.Accept(&printer);

		xmlStr = printer.CStr();
	}
	catch(std::exception& e)
	{
		Throw(rgcpp::IllegalArgumentException(std::string("Unable to create rpc inform request xml - ")+e.what()));
	}

	return xmlStr;
}

std::string HttpACSInterface::getDeviceSHA(const int id)
{
	Device device = DataBase::getInstance()->getDevice(id);

	if(!device.getSHA().empty())
		return device.getSHA();

	char digest[SHA_DIGEST_SIZE];
	rgcpp::SHAGenerator shaGenerator;

	shaGenerator.init();

	shaGenerator.update((char*)&id,sizeof(int));

	std::vector<Command> commands = DataBase::getInstance()->getDeviceCommands(id);
	for(std::vector<Command>::iterator itr=commands.begin(); itr!=commands.end(); itr++)
	{
		shaGenerator.update(itr->getCommand().c_str(),itr->getCommand().size());
		shaGenerator.update(itr->argumentsToString().c_str(),itr->argumentsToString().size());
	}

	if(!device.getConfigFileName().empty())
	{
		shaGenerator.update(device.getConfigFileName().c_str(),device.getConfigFileName().size());
		std::string filePath = ACSConfig::getDataDirectory()+std::string("Device_BackupRestore_")+rgcpp::ToString(device.getID());
		if(boost::filesystem::exists(filePath))
		{
			int varInt = boost::filesystem::last_write_time(filePath);
			shaGenerator.update((char*)&varInt,sizeof(int));
			boost::uintmax_t varUIntmax_t = boost::filesystem::file_size(filePath);
			shaGenerator.update((char*)&varUIntmax_t,sizeof(boost::uintmax_t));
		}
	}

	shaGenerator.digest(digest);

	device.setSHA(rgcpp::ToHex(digest,SHA_DIGEST_SIZE));

	DataBase::getInstance()->updateDevice(device);

	return device.getSHA();
}

}

extern "C" PION_SERVICE_API acs::HttpACSInterface* pion_create_HttpACSInterface(void)
{
	return new acs::HttpACSInterface();
}

extern "C" PION_SERVICE_API void pion_destroy_HttpACSInterface(acs::HttpACSInterface *service_ptr)
{
	delete service_ptr;
}
